﻿using System;
using SharpStockLib.Fin;
using SharpBackTestLib.Indicators;
using SharpStockLib.Data;
using SharpBackTestLib.Orders;

namespace SharpBackTestLib.Strategies
{
    /// <summary>
    /// Manages the indicators and signals that need to be sent to anyone listening to them (account managers, risk managers, etc...)
    /// </summary>
    public class SMACrossoverSignalManager
    {
        public IInstrument Instrument { get; set; }

        private readonly SimpleMovingAverage _smaShort;
        private readonly SimpleMovingAverage _smaLong;

        private double? _previousSmaShortValue;
        private double? _previousSmaLongValue;
        private double _previousClose;

        /// <summary>
        /// Constructor. Will actually build the indicators.
        /// </summary>
        /// <param name="periodShort">Period of the short-term SMA.</param>
        /// <param name="periodLong">Period of the long-term SMA.</param>
        public SMACrossoverSignalManager(int periodShort, int periodLong)
        {
            _smaShort = new SimpleMovingAverage(periodShort);
            _smaLong = new SimpleMovingAverage(periodLong);
        }

        /// <summary>
        /// Updates the indicators with the new data and manages new signals accordingly.
        /// </summary>
        /// <param name="data"></param>
        public ESignalType OnNewData(IData data)
        {
            // Stores previous values
            try
            {
                _previousSmaShortValue = _smaShort.GetValue();
                _previousSmaLongValue = _smaLong.GetValue();
            }
            catch (NotEnoughDataException e)
            {
                // Nothing much to do here.
                Console.WriteLine(e.Message);
            }

            // Updates the values
            _smaShort.OnNewData(data);
            _smaLong.OnNewData(data);

            // Manages signals
            ESignalType result = ManageSignals(data);
            
            _previousClose = data.Close;

            return result;
        }

        /// <summary>
        /// Will actually enforce the rules of the strategy. Once all the data are available, this is where the strat's rules are applied and signals are sent accordingly.
        /// </summary>
        /// <param name="data">The current price.</param>
        public ESignalType ManageSignals(IData data)
        {
            if (_previousClose > 0)
            {
                // Initiates a long position
                if (_previousClose < data.Close
                    && (_previousClose < _previousSmaShortValue || _previousSmaShortValue < _previousSmaLongValue) // previous close was below short SMA OR short SMA was below long SMA
                    && _smaShort.GetValue() > _smaLong.GetValue() && data.Close > _smaShort.GetValue()) // current close is above short SMA
                {
                    // Sends BUY signal
                    return ESignalType.Buy;
                }

                // Covers long position
                if (_previousClose > _previousSmaShortValue                                    // previous close was above SMA 20
                    && _smaShort.GetValue() > _smaLong.GetValue() && data.Close < _smaShort.GetValue())// current close is below SMA 20
                {
                    // Sends BUY COVER
                    return ESignalType.CoverBuy;
                }

                // Initiates a short position
                if (_previousClose > data.Close
                    && (_previousClose > _previousSmaShortValue || _previousSmaShortValue > _previousSmaLongValue) // previous close was above short SMA OR short SMA was still above long SMA
                    && _smaShort.GetValue() < _smaLong.GetValue() && data.Close < _smaShort.GetValue()) // current close is below SMA 20 and SMA 20 is below SMA 50
                {
                    // Sends SHORT signal
                    return ESignalType.Sell;
                }

                // Covers short position
                if (_previousClose < _previousSmaShortValue                                    // previous close was below SMA 20
                    && _smaShort.GetValue() < _smaLong.GetValue() && data.Close > _smaShort.GetValue())// current close is above SMA 20
                {
                    // Sends SHORT COVER
                    return ESignalType.CoverSell;
                }
            }

            return ESignalType.NoSignal;
        }
    }
}
